home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1992-1993 Michael Davidson.
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software
- * and its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation.
- *
- * This software is provided "as is" without express or implied warranty.
- */
-
- /*
- * This software is derived from the Independent JPEG Group's software
- *
- * Copyright (C) 1991, 1992 Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- *
- * For conditions of distribution and use, see the accompanying README file.
- */
-
- #include <stdio.h>
- #include "jpeg.h"
- #include "image.h"
-
- STATIC image_t *JPEGImage;
-
- typedef enum { /* JPEG marker codes */
- M_SOF0 = 0xc0,
- M_SOF1 = 0xc1,
- M_SOF2 = 0xc2,
- M_SOF3 = 0xc3,
-
- M_SOF5 = 0xc5,
- M_SOF6 = 0xc6,
- M_SOF7 = 0xc7,
-
- M_JPG = 0xc8,
- M_SOF9 = 0xc9,
- M_SOF10 = 0xca,
- M_SOF11 = 0xcb,
-
- M_SOF13 = 0xcd,
- M_SOF14 = 0xce,
- M_SOF15 = 0xcf,
-
- M_DHT = 0xc4,
-
- M_DAC = 0xcc,
-
- M_RST0 = 0xd0,
- M_RST1 = 0xd1,
- M_RST2 = 0xd2,
- M_RST3 = 0xd3,
- M_RST4 = 0xd4,
- M_RST5 = 0xd5,
- M_RST6 = 0xd6,
- M_RST7 = 0xd7,
-
- M_SOI = 0xd8,
- M_EOI = 0xd9,
- M_SOS = 0xda,
- M_DQT = 0xdb,
- M_DNL = 0xdc,
- M_DRI = 0xdd,
- M_DHP = 0xde,
- M_EXP = 0xdf,
-
- M_APP0 = 0xe0,
- M_APP1 = 0xe1,
- M_APP2 = 0xe2,
- M_APP3 = 0xe3,
- M_APP4 = 0xe4,
- M_APP5 = 0xe5,
- M_APP6 = 0xe6,
- M_APP7 = 0xe7,
- M_APP8 = 0xe8,
- M_APP9 = 0xe9,
- M_APP10 = 0xea,
- M_APP11 = 0xeb,
- M_APP12 = 0xec,
- M_APP13 = 0xed,
- M_APP14 = 0xee,
- M_APP15 = 0xef,
-
- M_JPG0 = 0xf0,
- M_JPG1 = 0xf1,
- M_JPG2 = 0xf2,
- M_JPG3 = 0xf3,
- M_JPG4 = 0xf4,
- M_JPG5 = 0xf5,
- M_JPG6 = 0xf6,
- M_JPG7 = 0xf7,
- M_JPG8 = 0xf8,
- M_JPG9 = 0xf9,
- M_JPG10 = 0xfa,
- M_JPG11 = 0xfb,
- M_JPG12 = 0xfc,
- M_JPG13 = 0xfd,
- M_COM = 0xfe,
-
- M_TEM = 0x01,
-
- } JPEG_MARKER;
-
- STATIC int jpegNextMarker(FILE *);
- STATIC void jpegSkipMarker(FILE *, int);
-
- /*
- * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
- * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
- * The conversion equations to be implemented are therefore
- * R = Y + 1.40200 * Cr
- * G = Y - 0.34414 * Cb - 0.71414 * Cr
- * B = Y + 1.77200 * Cb
- * where Cb and Cr represent the incoming values less MAXJSAMPLE/2.
- * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
- *
- * To avoid floating-point arithmetic, we represent the fractional constants
- * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
- * the products by 2^16, with appropriate rounding, to get the correct answer.
- * Notice that Y, being an integral input, does not contribute any fraction
- * so it need not participate in the rounding.
- *
- * For even more speed, we avoid doing any multiplications in the inner loop
- * by precalculating the constants times Cb and Cr for all possible values.
- * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
- * for 12-bit samples it is still acceptable. It's not very reasonable for
- * 16-bit samples, but if you want lossless storage you shouldn't be changing
- * colorspace anyway.
- * The Cr=>R and Cb=>B values can be rounded to integers in advance; the
- * values for the G calculation are left scaled up, since we must add them
- * together before rounding.
- */
-
- #define SCALEBITS 16 /* speedier right-shift on some machines */
- #define ONE_HALF (1L << (SCALEBITS-1))
- #define FIX(x) ((long) ((x) * (1L<<SCALEBITS) + 0.5))
-
- int Cr_r_tab[256]; /* => table for Cr to R conversion */
- int Cb_b_tab[256]; /* => table for Cb to B conversion */
- int Cr_g_tab[256]; /* => table for Cr to G conversion */
- int Cb_g_tab[256]; /* => table for Cb to G conversion */
-
- /*
- * Initialize for colorspace conversion.
- */
-
- ycc_rgb_init()
- {
- register int i, x2;
-
- for (i = 0; i < 256; i++)
- {
- /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
- /* The Cb or Cr value we are thinking of is x = i - MAXJSAMPLE/2 */
- x2 = 2*i - 255; /* twice x */
- /* Cr=>R value is nearest int to 1.40200 * x */
- Cr_r_tab[i] = (int) (FIX(1.40200/2) * x2 + ONE_HALF) >> SCALEBITS;
- /* Cb=>B value is nearest int to 1.77200 * x */
- Cb_b_tab[i] = (int) (FIX(1.77200/2) * x2 + ONE_HALF) >> SCALEBITS;
- /* Cr=>G value is scaled-up -0.71414 * x */
- Cr_g_tab[i] = (- FIX(0.71414/2)) * x2;
- /* Cb=>G value is scaled-up -0.34414 * x */
- /* We also add in ONE_HALF so that need not do it in inner loop */
- Cb_g_tab[i] = (- FIX(0.34414/2)) * x2 + ONE_HALF;
- }
- }
-
- #if !defined(ASM)
- ycc_to_rgb(
- unsigned char *y_ptr,
- unsigned char *cb_ptr,
- unsigned char *cr_ptr,
- unsigned char *rgb_ptr,
- int count
- )
- {
- register int cb, cr;
- extern unsigned char *range_limit_0_255;
-
- while (--count >= 0)
- {
- register unsigned char *range_limit;
-
- range_limit = &range_limit_0_255[*y_ptr++];
- cb = *cb_ptr++;
- cr = *cr_ptr++;
-
- /* red */
- *rgb_ptr++ = range_limit[Cr_r_tab[cr]];
- /* green */
- *rgb_ptr++ = range_limit[(Cb_g_tab[cb]+Cr_g_tab[cr]) >> SCALEBITS];
- /* blue */
- *rgb_ptr++ = range_limit[Cb_b_tab[cb]];
- }
- }
- #endif
-
- int
- jpegPutPixelsYCC(
- int col,
- int row,
- int width,
- int height,
- JSAMPLE ***pixel_data
- )
- {
- register int i;
-
- for (i = 0; i < height; i++)
- ycc_to_rgb(pixel_data[0][i], pixel_data[1][i], pixel_data[2][i],
- JPEGImage->pixels[row+i], width);
- return imageRefresh(col, row, width, height);
- }
-
- int
- jpegPutPixelsGS(
- int col,
- int row,
- int width,
- int height,
- JSAMPLE ***pixel_data
- )
- {
- int i;
- int r;
-
- for (i = 0; i < height; i++)
- if ((r = imagePutPixels(col, row++, pixel_data[0][i], width)) != 0)
- return r;
-
- return 0;
- }
-
- jpegError(format, a0)
- char *format;
- {
- return imageError(format, a0);
- }
-
- char *
- jpegInfo(
- FILE *fp
- )
- {
- int m;
- int precision, width, height, num_components;
- static char info[80];
- char *p;
-
- /* Expect an SOI marker first */
- if (jpegNextMarker(fp) != M_SOI)
- return NULL;
-
- while ((m = jpegNextMarker(fp)) != M_EOI && m != EOF)
- {
- switch (m)
- {
- case M_SOF0: case M_SOF1: case M_SOF2: case M_SOF3:
- case M_SOF5: case M_SOF6: case M_SOF7: case M_SOF9:
- case M_SOF10: case M_SOF11: case M_SOF13: case M_SOF14:
- case M_SOF15:
- (void) jpegGetWord(fp);
- precision = getc(fp);
- height = jpegGetWord(fp);
- width = jpegGetWord(fp);
- num_components = getc(fp);
- if (num_components == 1)
- p = "8 bit grayscale";
- else if (num_components == 3)
- p = "24 bit color";
- else
- p = "unknown color space";
- sprintf(info, "JPEG %dx%d %s", width, height, p);
- return info;
-
- case M_RST0: case M_RST1: case M_RST2: case M_RST3:
- case M_RST4: case M_RST5: case M_RST6: case M_RST7:
- break;
-
- default:
- jpegSkipMarker(fp, m);
- break;
- }
- }
-
- return NULL;
- }
-
- jpegRead(
- char *name,
- FILE *fp
- )
- {
- int m;
- int r = 0;
- struct decompress_info_struct cinfo;
- JPEG_TABLES jtables;
- int restart_interval;
-
- /* Expect an SOI marker first */
- if (jpegNextMarker(fp) != M_SOI)
- return jpegError("File does not start with JPEG SOI marker", 0);
-
- restart_interval = 0;
-
- while ((m = jpegNextMarker(fp)) != M_EOI && m != EOF && r == 0)
- {
- switch (m)
- {
- case M_SOF0:
- case M_SOF1: case M_SOF2: case M_SOF3: case M_SOF5:
- case M_SOF6: case M_SOF7: case M_SOF9: case M_SOF10:
- case M_SOF11: case M_SOF13: case M_SOF14: case M_SOF15:
- r = jpegSOF(fp, m, &cinfo);
- break;
-
- case M_DHT:
- r = jpegDHT(fp, &jtables);
- break;
-
- case M_SOS:
- if ((r = jpegSOS(fp, &cinfo)) != 0)
- break;
-
- if (cinfo.comps_in_scan == 1)
- {
- if ((JPEGImage = imageStart(name, cinfo.image_width,
- cinfo.image_height, 8, 0)) == NULL)
- {
- r = imageError("can't allocate %dx%d 8 bit JPEG image",
- cinfo.image_width, cinfo.image_height);
- break;
- }
-
- imageSetGrayColorMap(255);
- imageShowInfo(1);
-
- r = jpegScanDecode(fp, &cinfo, &jtables, restart_interval,
- jpegPutPixelsGS);
- }
- else if (cinfo.comps_in_scan == 3) /* color (YCbCr) */
- {
- ycc_rgb_init();
- if ((JPEGImage = imageStart(name, cinfo.image_width,
- cinfo.image_height, 24, 0)) == NULL)
- {
- r = imageError("can't allocate %dx%d 24 bit JPEG image",
- cinfo.image_width, cinfo.image_height);
- break;
- }
-
- imageShowInfo(1);
- r = jpegScanDecode(fp, &cinfo, &jtables, restart_interval,
- jpegPutPixelsYCC);
- }
- else
- r = jpegError("unknown JPEG colorspace", 0);
-
- break;
-
- case M_DAC:
- r = jpegError("Arithmetic coding not supported", 0);
- break;
-
- case M_DQT:
- r = jpegDQT(fp, &jtables);
- break;
-
- case M_DRI:
- r = jpegDRI(fp, &restart_interval);
- break;
-
- case M_RST0: case M_RST1: case M_RST2: case M_RST3:
- case M_RST4: case M_RST5: case M_RST6: case M_RST7:
- break;
-
- default:
- jpegSkipMarker(fp, m);
- break;
- }
- }
-
- if (r != 0)
- return r;
-
- if (m != M_EOI && (r = imageWarning("missing EOI marker")) != 0)
- return r;
-
- return imageEnd();
- }
-
- /*
- * Routines to parse JPEG markers & save away the useful info.
- */
-
- STATIC int
- jpegSOF(
- FILE *fp,
- int marker,
- decompress_info_ptr cinfo
- )
- /* Process a SOFn marker */
- {
- int length;
- int ci;
- int c;
- jpeg_component_info *compptr;
-
- if (marker != M_SOF0)
- return jpegError("unsupported SOF marker %02x", marker);
-
- length = jpegGetWord(fp);
-
- cinfo->data_precision = getc(fp);
- cinfo->image_height = jpegGetWord(fp);
- cinfo->image_width = jpegGetWord(fp);
- cinfo->num_components = getc(fp);
-
- /* We don't support files in which the image height is initially specified */
- /* as 0 and is later redefined by DNL. As long as we have to check that, */
- /* might as well have a general sanity check. */
- if (cinfo->image_height <= 0 || cinfo->image_width <= 0 || cinfo->num_components <= 0)
- return jpegError("Empty JPEG image (DNL not supported)", 0);
-
- if (cinfo->data_precision != 8)
- return jpegError("Unsupported JPEG data precision", 0);
-
- if (length != (cinfo->num_components * 3 + 8))
- return jpegError("Bogus SOF length", 0);
-
- for (ci = 0; ci < cinfo->num_components; ci++)
- {
- compptr = &cinfo->comp_info[ci];
- compptr->component_index= ci;
- compptr->component_id = getc(fp);
- c = getc(fp);
- compptr->h_samp_factor = (c >> 4) & 0x0f;
- compptr->v_samp_factor = c & 0x0f;
- compptr->quant_tbl_no = getc(fp);
- }
- return 0;
- }
-
-
- STATIC int
- jpegSOS(
- FILE *fp,
- decompress_info_ptr cinfo
- )
- /* Process a SOS marker */
- {
- int length;
- int i, ci, n, c, cc;
- jpeg_component_info * compptr;
-
- length = jpegGetWord(fp);
- n = getc(fp);
- cinfo->comps_in_scan = n;
- length -= 3;
-
- if (length != (n * 2 + 3) || n < 1 || n > MAX_COMPS_IN_SCAN)
- return jpegError("Bogus SOS length", 0);
-
- for (i = 0; i < n; i++)
- {
- cc = getc(fp);
- c = getc(fp);
- length -= 2;
-
- for (ci = 0; ci < cinfo->num_components; ci++)
- if (cc == cinfo->comp_info[ci].component_id)
- break;
-
- if (ci >= cinfo->num_components)
- return jpegError("Invalid component number in SOS", 0);
-
- compptr = &cinfo->comp_info[ci];
- cinfo->cur_comp_info[i] = compptr;
- compptr->dc_tbl_no = (c >> 4) & 15;
- compptr->ac_tbl_no = (c ) & 15;
- }
-
- (void) getc(fp);
- (void) getc(fp);
- (void) getc(fp);
-
- return 0;
- }
-
- /*
- * jpegDRI() - process a DRI marker
- */
- int
- jpegDRI(
- FILE *fp,
- int *interval
- )
- {
- if (jpegGetWord(fp) != 4)
- return jpegError("Bogus length in DRI", 0);
-
- *interval = jpegGetWord(fp);
-
- return 0;
- }
-
- /*
- * jpegNextMarker(fp)
- *
- * - returns next JPEG marker or EOF
- */
- STATIC int
- jpegNextMarker (
- FILE *fp
- )
- {
- int c;
-
- do
- {
- while ((c = getc(fp)) != EOF && c != 0xff)
- continue;
-
- while ((c = getc(fp)) != EOF && c == 0xff)
- continue;
- } while (c == 0);
-
- return c;
- }
-
- /*
- * jpegSkipMarker(fp, m)
- *
- * - skips a variable length JPEG marker
- */
- /*ARGSUSED*/
- STATIC void
- jpegSkipMarker(
- FILE *fp,
- int marker
- )
- {
- int length;
-
- length = jpegGetWord(fp);
-
- for (length -= 2; length > 0; length--)
- (void) getc(fp);
- }
-
- int
- jpegGetWord(
- FILE *fp
- )
- {
- unsigned short a;
-
- a = getc(fp);
- return (a << 8) + getc(fp);
- }
-
- int
- jpegGetByte(
- FILE *fp
- )
- {
- return getc(fp);
- }
-